// File: jmcomic-core/src/main/java/dev/jukomu/jmcomic/entity/JmPhotoDetail.java
package dev.jukomu.jmcomic.entity;

import dev.jukomu.common.util.Asserts;
import dev.jukomu.common.util.time.TimeUtils;
import dev.jukomu.jmcomic.config.JmModuleConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 对应Python的JmPhotoDetail，表示禁漫的章节详情。
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class JmPhotoDetail extends DetailEntity<JmImageDetail> implements Downloadable {

    private String photoId;
    private String scrambleId; // 章节解密ID
    private String name; // 章节名称/标题
    private int sort; // 章节在本子中的排序（从1开始）
    private String tagsString; // 原始标签字符串（可能以逗号分隔或空格分隔）
    private int seriesId; // 如果是系列本子中的章节，表示本子ID；否则为0（单章节本子）

    private String author; // 章节作者（如果来自API且没有父本子）
    private JmAlbumDetail fromAlbum; // 章节所属本子的引用

    // 与图片URL有关的属性
    private List<String> pageArr; // 图片文件名列表（不含路径，不含查询参数）
    private String dataOriginalDomain; // 图片CDN域名
    private String dataOriginal0; // 第一张图片URL（可能含查询参数，用于提取queryParams）
    private String dataOriginalQueryParams; // 图片URL的查询参数，例如 ?v=时间戳

    // Downloadable接口的字段
    private String savePath;
    private boolean exists;
    private boolean skip;

    // 缓存JmImageDetail实例
    private transient Map<Integer, JmImageDetail> imageDetailCache = new ConcurrentHashMap<>();

    /**
     * 构造函数。
     *
     * @param photoId            章节ID
     * @param name               章节名称
     * @param seriesId           系列ID（本子ID），如果为0表示单章节本子
     * @param sort               章节排序
     * @param tagsString         标签字符串
     * @param scrambleId         章节解密ID
     * @param pageArr            图片文件名列表
     * @param dataOriginalDomain 图片CDN域名
     * @param dataOriginal0      第一张图片原始URL
     * @param author             章节作者
     * @param fromAlbum          章节所属本子的引用
     */
    public JmPhotoDetail(String photoId, String name, int seriesId, int sort, String tagsString, String scrambleId, List<String> pageArr, String dataOriginalDomain, String dataOriginal0, String author, JmAlbumDetail fromAlbum) {
        this.photoId = photoId;
        this.name = name != null ? name.trim() : "";
        this.seriesId = seriesId;
        this.sort = sort;
        this.tagsString = tagsString != null ? tagsString : "";
        this.scrambleId = scrambleId != null ? scrambleId : "";
        this.pageArr = pageArr != null ? pageArr : Collections.emptyList();
        this.dataOriginalDomain = dataOriginalDomain;
        this.dataOriginal0 = dataOriginal0;
        this.author = author;
        this.fromAlbum = fromAlbum;

        // 根据dataOriginal0初始化dataOriginalQueryParams
        this.dataOriginalQueryParams = getDataOriginalQueryParams(dataOriginal0);
    }

    /**
     * 默认构造函数（用于JSON反序列化）。
     */
    public JmPhotoDetail() {
        this(null, null, 0, 0, null, null, null, null, null, null, null);
    }

    /**
     * 辅助构造函数，简化创建。
     *
     * @param photoId    章节ID
     * @param scrambleId 章节解密ID
     * @param name       章节名称
     * @param seriesId   系列ID
     * @param sort       章节排序
     * @param fromAlbum  所属本子
     */
    public JmPhotoDetail(String photoId, String scrambleId, String name, int seriesId, int sort, JmAlbumDetail fromAlbum) {
        this(photoId, name, seriesId, sort, null, scrambleId, null, null, null, null, fromAlbum);
    }

    /**
     * 判断是否为单章节本子。
     *
     * @return 如果是单章节本子返回 true
     */
    public boolean isSingleAlbum() {
        return seriesId == 0;
    }

    /**
     * 获取章节的标签列表。
     * 优先使用所属本子的标签，否则解析自身的标签字符串。
     *
     * @return 标签列表
     */
    public List<String> getTags() {
        if (fromAlbum != null) {
            return fromAlbum.getTags();
        }

        if (tagsString.contains(",")) {
            return Arrays.asList(tagsString.split(","));
        } else {
            return Arrays.asList(tagsString.split(" ")); // 假设API返回的是空格分隔
        }
    }

    /**
     * 获取章节的ID。
     *
     * @return 章节ID字符串
     */
    @Override
    public String getId() {
        return photoId;
    }

    /**
     * 获取章节的标题。
     *
     * @return 章节标题字符串
     */
    @Override
    public String getTitle() {
        return name;
    }

    /**
     * 获取章节在本子中的排序标题。
     * 格式："第X话 章节名称"
     *
     * @return 排序标题字符串
     */
    public String getIndexTitle() {
        return String.format("第%d话 %s", getAlbumIndex(), name);
    }

    /**
     * 获取章节所属本子的ID。
     *
     * @return 本子ID字符串
     */
    public String getAlbumId() {
        return isSingleAlbum() ? photoId : String.valueOf(seriesId);
    }

    /**
     * 获取章节在本子中的索引（从1开始）。
     *
     * @return 章节索引
     */
    public int getAlbumIndex() {
        // 如果是单章本子，JM给的sort为2。这里返回1比较符合语义定义。
        if (isSingleAlbum() && sort == 2) {
            return 1;
        }
        return sort;
    }

    /**
     * 获取章节的作者。
     * 优先使用所属本子的作者，否则使用自身作者属性，最后使用默认作者。
     *
     * @return 作者字符串
     */
    @Override
    public String getAuthor() {
        if (fromAlbum != null) {
            return fromAlbum.getAuthor();
        }
        if (author != null && !author.isEmpty()) {
            return author.trim();
        }
        return JmModuleConfig.DEFAULT_AUTHOR;
    }

    /**
     * 创建指定索引的图片详情实例。
     *
     * @param index 图片索引（从0开始）
     * @return JmImageDetail实例
     * @throws IndexOutOfBoundsException 如果索引超出范围
     */
    @Override
    public JmImageDetail get(int index) {
        if (index < 0 || index >= pageArr.size()) {
            throw new IndexOutOfBoundsException(String.format("Image index out of range for photo-%s: %d >= %d", photoId, index, pageArr.size()));
        }

        // 实现lru_cache，缓存JmImageDetail实例
        return imageDetailCache.computeIfAbsent(index, i -> {
            String dataOriginal = getImgDataOriginal(pageArr.get(i));
            return (JmImageDetail) JmModuleConfig.getImageClass().cast(
                    JmImageDetail.of(
                            photoId,
                            scrambleId,
                            dataOriginal,
                            this,
                            dataOriginalQueryParams,
                            i + 1 // 索引从1开始
                    )
            );
        });
    }

    /**
     * 获取章节中图片的数量。
     *
     * @return 图片数量
     */
    @Override
    public int size() {
        return pageArr.size();
    }

    /**
     * 根据图片文件名生成完整的图片请求URL。
     *
     * @param imgName 图片文件名（例如 "01111.webp"）
     * @return 完整的图片URL
     */
    public String getImgDataOriginal(String imgName) {
        String domain = dataOriginalDomain;
        // 确保域名不为空，否则抛出异常
        Asserts.requireTrue(domain != null && !domain.isEmpty(), "Image domain is empty for photo: " + photoId);
        return String.format("%s%s/media/photos/%s/%s", JmModuleConfig.PROT, domain, photoId, imgName);
    }

    /**
     * 从第一张图片URL中提取查询参数。
     *
     * @param dataOriginal0 第一张图片URL
     * @return 查询参数字符串（例如 "v=时间戳"）
     */
    private String getDataOriginalQueryParams(String dataOriginal0) {
        if (dataOriginal0 == null) {
            return "v=" + TimeUtils.timestamp();
        }
        int queryIndex = dataOriginal0.lastIndexOf('?');
        if (queryIndex == -1) {
            return "v=" + TimeUtils.timestamp();
        }
        return dataOriginal0.substring(queryIndex + 1);
    }

    @Override
    public boolean isPhoto() {
        return true;
    }

    // --- Getters for fields ---
    public String getPhotoId() {
        return photoId;
    }

    public String getScrambleId() {
        return scrambleId;
    }

    public String getName() {
        return name;
    }

    public int getSort() {
        return sort;
    }

    public String getTagsString() {
        return tagsString;
    }

    public int getSeriesId() {
        return seriesId;
    }

    public List<String> getPageArr() {
        return pageArr;
    }

    public String getDataOriginalDomain() {
        return dataOriginalDomain;
    }

    public String getDataOriginal0() {
        return dataOriginal0;
    }

    public String getDataOriginalQueryParams() {
        return dataOriginalQueryParams;
    }

    // --- Setters for Downloadable interface ---
    @Override
    public String getSavePath() {
        return savePath;
    }

    @Override
    public void setSavePath(String savePath) {
        this.savePath = savePath;
    }

    @Override
    public boolean isExists() {
        return exists;
    }

    @Override
    public void setExists(boolean exists) {
        this.exists = exists;
    }

    @Override
    public boolean isSkip() {
        return skip;
    }

    @Override
    public void setSkip(boolean skip) {
        this.skip = skip;
    }

    // --- Setters for other properties if needed for external modification ---
    // These setters are crucial for clients to update photo details after fetching,
    // e.g., setting fromAlbum, pageArr, dataOriginalDomain, scrambleId.
    public void setPhotoId(String photoId) {
        this.photoId = photoId;
    }

    public void setScrambleId(String scrambleId) {
        this.scrambleId = scrambleId;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSort(int sort) {
        this.sort = sort;
    }

    public void setTagsString(String tagsString) {
        this.tagsString = tagsString;
    }

    public void setSeriesId(int seriesId) {
        this.seriesId = seriesId;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public void setFromAlbum(JmAlbumDetail fromAlbum) {
        this.fromAlbum = fromAlbum;
    }

    public void setPageArr(List<String> pageArr) {
        this.pageArr = pageArr;
    }

    public void setDataOriginalDomain(String dataOriginalDomain) {
        this.dataOriginalDomain = dataOriginalDomain;
    }

    public void setDataOriginal0(String dataOriginal0) {
        this.dataOriginal0 = dataOriginal0;
        this.dataOriginalQueryParams = getDataOriginalQueryParams(dataOriginal0);
    }
}